Heatmap of significant genes per cluster

Load data and libraries

##################
# LOAD LIBRARIES #
##################
library(tidyverse)
library(Seurat)
library(SeuratObject)
library(tidyseurat)
library(cowplot)
library(patchwork)
library(openxlsx)

source("../../bin/spatial_visualization.R")
source("../../bin/plotting_functions.R")

#########
# PATHS #
#########
input_dir <- "../../results/06_DGE_condition_st_data/"
result_dir <- "./Figures/05/"
if( isFALSE(dir.exists(result_dir)) ) { dir.create(result_dir,recursive = TRUE) }
epi_clus <- "^5$|^6$|^7|^8" # res 0.7

ord <- c("Superficial", "Upper IM", "Lower IM", "Basal","1","4","0","3","2","9","10","11","12")
ord1 <- c("5", "6", "7", "8","1","4","0","3","2","9","10","11","12")
sample_id <- c("P020", "P045", "P050", "P057",
               "P008", "P031", "P044","P080", "P026", "P105", 
               "P001", "P004", "P014", "P018", "P087", "P118",
               "P021", "P024", "P067", "P081", "P117" ) %>% set_names()

#############
# LOAD DATA #
#############
DATA <- readRDS(paste0("../../results/03_clustering_st_data/","seuratObj_clustered.RDS"))
DEGs_table <- read_csv(paste0(input_dir,"DGEs_condition_wilcox.0.7.csv"))
pseudo_DEGs <- readRDS(paste0(input_dir,"Pseudobulk_across_DEGs.RDS"))
D <- DEGs_table %>%
  filter(., p_val_adj < 0.05) %>%
  filter(., !(grepl("0|^3|9|10|11|12", .$subgroup))) %>%
  #filter(., cluster == "L4") %>%
  mutate(sp_annot = ifelse(grepl("\\d", .$layers), "SubMuc", "epi")) %>%
  split(~sp_annot) 
# NOT USED
#################
# PLOT FUNCTION #
#################
morf_DEGs_plot <- function(genes = genes_epi, clus="^5$|^6$|^7|^8"){
  df <- DATA %>%
    mutate(., FetchData(., vars = c(names(genes)), slot = "counts")) %>%
    filter(., grepl(clus, .$Clusters)) %>%
    as_tibble() %>%
    select(1:5, layers, all_of(names(genes))) %>%
    pivot_longer(cols = any_of(names(genes)), names_to = "gene", values_to = "values") %>%
    # filter(gene == "LGALS7") %>%
    group_by( groups, gene, layers) %>%
    summarize(sum_counts = sum(values), .groups="drop") %>%
    mutate("Sum counts(log10)" = log10(.$sum_counts)) %>%
    arrange(`Sum counts(log10)`) %>%
    mutate(type = genes[.$gene])
  
  absmax <- function(x) { x[which.max( abs(x) )]}
  ord <<- df %>%
    #pivot_wider(id_cols = -`Sum counts(log10)`,names_from = "groups", values_from = "sum_counts") %>%
    pivot_wider(id_cols = -sum_counts, names_from = "groups", values_from = `Sum counts(log10)`) %>%
    mutate(diff_L1_L4 = L4-L1, 
           diff_L2_L4 = L4-L2, 
           diff_L3_L4 = L4-L3, .by = "gene") %>%
    rowwise() %>% 
    # Identifies the larges value of eah row among the L1-L4 columns:
    mutate(Regulation = sum(c_across(starts_with("diff")) ),
           max = paste0(names(.[4:7])[c_across(starts_with("L",ignore.case=F)) == 
                                        absmax(c_across(starts_with("L",ignore.case=F)))], collapse = '_') ) %>%
    ungroup() %>%
    mutate(Regulation = ifelse(.$Regulation < 0, "DOWN", "UP"),
           max = str_extract(.$max, "L\\d"))
  
  m <- ifelse(clus == "^5$|^6$|^7|^8", "Epithelial", "Submucosal")
  #write.xlsx(ord, paste0(result_dir, "Selected_DEGs_FIG2-3_", m, ".xlsx"))
  #####################
  # TOP DEGs PLOTTING #
  #####################
  g_ord <- arrange(ord, diff_L1_L4) %>% pull("gene") %>% unique()
  
  col <- c("L1"="#FF7F00", "L2"="#FED9A6", "L3"="#6A51A3", "L4"="#9E9AC8" ) # "#FFFFB3", "#BEBADA","#8DD3C7", "#FB8072",
  col <- c("L1"="#56B4E9","L2"="#009E73","L3"="#CC79A7", "L4"="#FC8D62")
  
  (B <- left_join(df, select(ord, Regulation, max, gene), by="gene") %>%
      #mutate(., gene = factor(gene, levels=g_ord)) %>%
      ggplot2::ggplot(data=., aes(x=fct_reorder2(gene, Regulation,`Sum counts(log10)`), y=`Sum counts(log10)`)) +
    geom_point(aes(col=groups), size = 2) +
    scale_colour_manual(values = col) +
    facet_grid(cols=vars(), rows = vars(layers), scales = "free_x", space = "free_x") +
    #facet_wrap("max", ncol = 2, strip.position = "top", scales = "free_x", shrink = F) +
    theme_minimal() +
    theme(legend.position = "bottom",
          plot.margin = unit(c(5,-1,5,1),units = "pt"),
          legend.margin = margin(-15,2,-8,2), # moves the legend box
          legend.title = element_blank(),
          legend.text = element_text(size = 8),
          legend.spacing.x = unit(4, 'pt'),
          axis.title = element_text(size=8),
          axis.text.x = element_text(size=8, angle=45, hjust=1, color="black"),
          axis.title.x = element_blank(),
          #text = element_text(size = 10),
    ) )
}
geneid  <- c("IGHG4", "IGLC2", "IGHG1", "IGHA2", "IGHA1")
genes <- DEGs_table %>% filter(gene %in% geneid) %>% filter(grepl("^1$|Basal", .$layers)) %>% distinct(gene, layers) %>% deframe()
(Immuno <- morf_DEGs_plot(genes = genes, clus="^1$|8"))
###############
# VIOLIN PLOT #
###############
# https://stackoverflow.com/questions/35717353/split-violin-plot-with-ggplot2

feature <- c("IGHG4", "IGLC2", "IGHG1", "IGHA2", "IGHA1", "CD81", "IGKC", "JCHAIN")
feature <- c("IGHA1","IGHG1", "CD81", "IGKC", "JCHAIN")
col <- c("L1"="#56B4E9","L2"="#009E73","L3"="#CC79A7", "L4"="#FC8D62")
facet <- "layers"
group.by <- "groups"
ncol <- 1

DEGs_df <- DATA %>%
  #filter(!(grepl("\\d", .$layers))) %>%
  filter((grepl("Basal|^1$", .$layers))) %>%
  filter((grepl("L1|L2", .$groups))) %>%
  mutate(., FetchData(., vars = c(feature)) ) %>%
  #mutate(across(any_of(feature), na_if, 0)) %>% # NB! removes zero values 
  select(any_of(c(feature, facet, group.by, "layers"))) %>%
  pivot_longer(cols = any_of(feature), names_to = "feature", values_to = "val") %>%
  mutate(comb = paste0(.$groups, "_",.$layers)) %>%
  mutate(groups = factor(.$groups, levels = sort(unique(.$groups))))

# groups on y-axis, genes on x axis
# not used:
violin_mean_plot <- function(DEGs_df){
  m <- max(na.omit(DEGs_df[["val"]]))/1 # try e.g 2
  DEGs_df %>%
    ggplot(aes(y=.data[[group.by]], x=.data[["val"]], col=.data[[group.by]])) +
    geom_violin() + # {if(length(feature == 1)) ggtitle(feature)} +
    #geom_boxplot(fill = "transparent", notch = T, outlier.size = .5, outlier.colour = "red") +
    geom_jitter(width = 0.2, height = 0.3, alpha = 0.2, size=.1) +
    stat_summary(aes(x = val), fun=median, geom="crossbar", linewidth=.3, color="black") +
    scale_color_manual(values = col) +
    my_theme + NoLegend() + #xlim(c(0, m)) +
    theme(text = element_text(size = 10)) +
    #       axis.text.x = element_text(angle = 30, hjust=1),
    #       plot.title = element_text(hjust = 0.5),
    #       axis.title.y = element_blank(),
    #       axis.title.x = element_blank()) +
    #facet_wrap(~.data[[facet]], ncol = ncol, strip.position = c("right", "bottom", "left", "top"))
    facet_grid(rows = vars(layers), cols = vars(feature)) #, strip.position = c("right", "bottom", "left", "top"))
}

# dev.new(width=6.7, height=3, noRStudioGD = TRUE) 
A <- violin_mean_plot(DEGs_df)
# ggsave("./Figures/04/Fig_viol.png", A, width = 6.7, height = 3) #, dpi = 300

# groups on x-axis, genes on x axis
# used for figure 4
violin_mean_plot <- function(DEGs_df){
  m <- max(na.omit(DEGs_df[["val"]]))/1 # try e.g 2
  DEGs_df %>%
    ggplot(aes(x=.data[[group.by]], y=.data[["val"]], col=.data[[group.by]])) +
    geom_violin() + # {if(length(feature == 1)) ggtitle(feature)} +
    stat_summary(aes(y = val), fun=median, geom="crossbar", linewidth=.3, color="black") +
    #geom_boxplot(fill = "transparent", notch = T, outlier.size = .5, outlier.colour = "red") +
    geom_jitter(width = 0.3, height = 0.2, alpha = 0.2, size=.01) +
    scale_color_manual(values = col) + ylab("Expression") +
    my_theme + NoLegend() + #xlim(c(0, m)) +
    theme(text = element_text(size = 12),
          axis.line = element_blank(),
          panel.border = element_rect(colour = "gray") ) +
    #       axis.text.x = element_text(angle = 30, hjust=1),
    #       plot.title = element_text(hjust = 0.5),
    #       axis.title.y = element_blank(),
    #       axis.title.x = element_blank()) +
    #facet_wrap(~.data[[facet]], ncol = ncol, strip.position = c("right", "bottom", "left", "top"))
    facet_grid(rows = vars(layers), cols = vars(feature)) #, strip.position = c("right", "bottom", "left", "top"))
}

# dev.new(width=3.3, height=3, noRStudioGD = TRUE) 
A <- violin_mean_plot(DEGs_df)
# ggsave("./Figures/04/Fig_L1_L2_viol.png", A, width = 4, height = 4, dpi = 500) #, dpi = 300
######################
# PLOTTING ON TISSUE #
######################
col = c("#EFEDF5", "#DADAEB", "#BCBDDC", "#9E9AC8", "#807DBA", "#6A51A3", "#54278F", "#3F007D")
geneid <- c("IGHG4", "IGLC2", "IGHG1", "IGHA2", "IGHA1", "CD81", "IGKC", "JCHAIN")

# ggsave("./Figures/02&03/Tissue_Immuno.png", p, width = 12.5, height = 12.5, bg = "white") #, dpi = 300
# dev.new(height=3, width=7, noRStudioGD = TRUE)
plots_all <- geneid %>%
  map(., ~plot_spatial.fun(
      DATA,
      sampleid = sample_id,
      save_space = T,
      colors = col, 
      geneid = .x,
      zoom = "zoom",
      ncol = 4,
      img_alpha = 0,
      point_size = .5)
    )

# dev.new(width=8, height=8, noRStudioGD = TRUE)
plots_all[[1]]

################
# SAVE RESULTS #
################
pdf(file=paste0("./Figures/04/Tissue_Immuno_all.pdf"), 
    #width = 8.5, height = 10 # Epi
    width = 8, height = 8 # Sub
)
plots_all
## [[1]]
## 
## [[2]]
## 
## [[3]]
## 
## [[4]]
## 
## [[5]]
## 
## [[6]]
## 
## [[7]]
## 
## [[8]]
dev.off()
## quartz_off_screen 
##                 2
######################
# PLOTTING ON TISSUE #
######################
sample_id_ <- c("P057","P044")


plots_rep <- geneid %>%
  map(., ~plot_spatial.fun(
      DATA,
      sampleid = sample_id_,
      save_space = F,
      colors = col, 
      geneid = .x,
      zoom = "zoom",
      ncol = 4,
      img_alpha = 0,
      point_size = .5)
    )
# dev.new(width=3.3, height=2, noRStudioGD = TRUE)
plots_rep[[1]]

B <- plot_grid(plots_rep[[8]], plots_rep[[5]], ncol = 1)
# ggsave("./Figures/04/on_tissue.png", B, width = 4, height = 3.3, bg = "white", dpi = 500) #, dpi = 300
#########################
# COMBINE PANEL A AND B #
#########################
# dev.new(width=6.7, height=3, noRStudioGD = TRUE) 
(FIGURE4 <- plot_grid(A, B, rel_widths = c(1, 1))) # labels = c("a", "b")

# ggsave("./Figures/04/Figure_4.png", p, width = 6.7, height = 3.3, bg = "white") #, dpi = 300
LS0tCnRpdGxlOiAiRmlndXJlIDQiCnN1YnRpdGxlOiAiSW1tdW5vZ2xvYnVsaW4gcGxvdHMiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkLSVtLSVZJylgIgpmb3JtYXQ6CiAgaHRtbDoKICAgIGVtYmVkLXJlc291cmNlczogdHJ1ZQogICAgY29kZS1mb2xkOiBzaG93CnBhcmFtczoKICBmaWcucGF0aDogImByIHBhc3RlMChwYXJhbXMkZmlnLnBhdGgpYCIgIy4vRmlndXJlcy8KZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCi0tLQojIyBIZWF0bWFwIG9mIHNpZ25pZmljYW50IGdlbmVzIHBlciBjbHVzdGVyCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGZpZy53aWR0aCAgICAgPSA2LjY5MjkxMzM4NTgsCiAgZmlnLnBhdGggICAgICA9IHBhcmFtcyRmaWcucGF0aCwjIi4uL0ZpZ3VyZXMvIiwKICBmaWcuYWxpZ24gICAgID0gImNlbnRlciIsCiAgbWVzc2FnZSAgICAgICA9IEZBTFNFLAogIHdhcm5pbmcgICAgICAgPSBGQUxTRSwKICBkZXYgICAgICAgICAgID0gYygicG5nIiksCiAgZHBpICAgICAgICAgICA9IDMwMCwKICBmaWcucHJvY2VzcyA9IGZ1bmN0aW9uKGZpbGVuYW1lKXsKICAgIG5ld19maWxlbmFtZSA8LSBzdHJpbmdyOjpzdHJfcmVtb3ZlKHN0cmluZyA9IGZpbGVuYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICItMSIpCiAgICBmczo6ZmlsZV9tb3ZlKHBhdGggPSBmaWxlbmFtZSwgbmV3X3BhdGggPSBuZXdfZmlsZW5hbWUpCiAgICBpZmVsc2UoZnM6OmZpbGVfZXhpc3RzKG5ld19maWxlbmFtZSksIG5ld19maWxlbmFtZSwgZmlsZW5hbWUpCiAgfQogICkKIyAgc2V0d2QoIn4vd29yay9Ccm9saWRlbnNfd29yay9Qcm9qZWN0cy9TcGF0aWFsX01pY3JvYmlvdGEvc3JjL01hbnVzY3JpcHQiKQpgYGAKCmBgYHtyIGJhY2tncm91bmRfam9iLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpzb3VyY2UoIi4uLy4uL2Jpbi9yZW5kZXJfd2l0aF9qb2JzLlIiKQoKIyBxdWFydG8KIyByZW5kZXJfaHRtbF93aXRoX2pvYihvdXRfZGlyID0gbGFiX2RpcikKIyBmczo6ZmlsZV9tb3ZlKHBhdGggPSBmaWxlLCBuZXdfcGF0aCA9IHBhc3RlMChsYWJfZGlyLCBmaWxlKSkKCiMgY3VycmVudGx5IHVzaW5nIHF1YXJ0byBmb3IgZ2l0aHViIGFuZCBrbml0ZXIgZm9yIGh0bWwgZHVlIHRvIHNvdXJjZSBjb2RlIG9wdGlvbiAKcmVuZGVyX2dpdF93aXRoX2pvYihmaWdfcGF0aCA9ICIuL0ZpZ3VyZXMvMDQvIikKc3lzdGVtMihjb21tYW5kID0gInNlZCIsIHN0ZG91dCA9IFRSVUUsCiAgICAgICAgYXJncyA9IGMoIi1pIiwgIicnIiwiLWUiLCAncy9zcmM9XFwiXFwuL3NyYz1cXCJcXC5cXC4vZycsCiAgICAgICAgICAgICAgICAgcGFzdGUwKCIuL21kX2ZpbGVzLyIsIGJhc2VuYW1lKCIuLzA0X2ZpZ3VyZXMubWQiKSkpKQoKIyBrbml0ZXIKa25pdF9odG1sX3dpdGhfam9iKG91dF9kaXIgPSAiLi4vLi4vbGFiX2Jvb2svZmlndXJlXzA0IiwgZmlnX3BhdGggPSAiLi9GaWd1cmVzLzA0LyIpCmBgYAoKIyMjIExvYWQgZGF0YSBhbmQgbGlicmFyaWVzCmBgYHtyIExvYWRfZGF0YX0KIyMjIyMjIyMjIyMjIyMjIyMjCiMgTE9BRCBMSUJSQVJJRVMgIwojIyMjIyMjIyMjIyMjIyMjIyMKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KFNldXJhdE9iamVjdCkKbGlicmFyeSh0aWR5c2V1cmF0KQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KG9wZW54bHN4KQoKc291cmNlKCIuLi8uLi9iaW4vc3BhdGlhbF92aXN1YWxpemF0aW9uLlIiKQpzb3VyY2UoIi4uLy4uL2Jpbi9wbG90dGluZ19mdW5jdGlvbnMuUiIpCgojIyMjIyMjIyMKIyBQQVRIUyAjCiMjIyMjIyMjIwppbnB1dF9kaXIgPC0gIi4uLy4uL3Jlc3VsdHMvMDZfREdFX2NvbmRpdGlvbl9zdF9kYXRhLyIKcmVzdWx0X2RpciA8LSAiLi9GaWd1cmVzLzA1LyIKaWYoIGlzRkFMU0UoZGlyLmV4aXN0cyhyZXN1bHRfZGlyKSkgKSB7IGRpci5jcmVhdGUocmVzdWx0X2RpcixyZWN1cnNpdmUgPSBUUlVFKSB9CmVwaV9jbHVzIDwtICJeNSR8XjYkfF43fF44IiAjIHJlcyAwLjcKCm9yZCA8LSBjKCJTdXBlcmZpY2lhbCIsICJVcHBlciBJTSIsICJMb3dlciBJTSIsICJCYXNhbCIsIjEiLCI0IiwiMCIsIjMiLCIyIiwiOSIsIjEwIiwiMTEiLCIxMiIpCm9yZDEgPC0gYygiNSIsICI2IiwgIjciLCAiOCIsIjEiLCI0IiwiMCIsIjMiLCIyIiwiOSIsIjEwIiwiMTEiLCIxMiIpCnNhbXBsZV9pZCA8LSBjKCJQMDIwIiwgIlAwNDUiLCAiUDA1MCIsICJQMDU3IiwKICAgICAgICAgICAgICAgIlAwMDgiLCAiUDAzMSIsICJQMDQ0IiwiUDA4MCIsICJQMDI2IiwgIlAxMDUiLCAKICAgICAgICAgICAgICAgIlAwMDEiLCAiUDAwNCIsICJQMDE0IiwgIlAwMTgiLCAiUDA4NyIsICJQMTE4IiwKICAgICAgICAgICAgICAgIlAwMjEiLCAiUDAyNCIsICJQMDY3IiwgIlAwODEiLCAiUDExNyIgKSAlPiUgc2V0X25hbWVzKCkKCiMjIyMjIyMjIyMjIyMKIyBMT0FEIERBVEEgIwojIyMjIyMjIyMjIyMjCkRBVEEgPC0gcmVhZFJEUyhwYXN0ZTAoIi4uLy4uL3Jlc3VsdHMvMDNfY2x1c3RlcmluZ19zdF9kYXRhLyIsInNldXJhdE9ial9jbHVzdGVyZWQuUkRTIikpCkRFR3NfdGFibGUgPC0gcmVhZF9jc3YocGFzdGUwKGlucHV0X2RpciwiREdFc19jb25kaXRpb25fd2lsY294LjAuNy5jc3YiKSkKcHNldWRvX0RFR3MgPC0gcmVhZFJEUyhwYXN0ZTAoaW5wdXRfZGlyLCJQc2V1ZG9idWxrX2Fjcm9zc19ERUdzLlJEUyIpKQoKYGBgCgpgYGB7cn0KRCA8LSBERUdzX3RhYmxlICU+JQogIGZpbHRlciguLCBwX3ZhbF9hZGogPCAwLjA1KSAlPiUKICBmaWx0ZXIoLiwgIShncmVwbCgiMHxeM3w5fDEwfDExfDEyIiwgLiRzdWJncm91cCkpKSAlPiUKICAjZmlsdGVyKC4sIGNsdXN0ZXIgPT0gIkw0IikgJT4lCiAgbXV0YXRlKHNwX2Fubm90ID0gaWZlbHNlKGdyZXBsKCJcXGQiLCAuJGxheWVycyksICJTdWJNdWMiLCAiZXBpIikpICU+JQogIHNwbGl0KH5zcF9hbm5vdCkgCmBgYAoKYGBge3IgZG90LXBsb3QsIGV2YWw9RkFMU0V9CiMgTk9UIFVTRUQKIyMjIyMjIyMjIyMjIyMjIyMKIyBQTE9UIEZVTkNUSU9OICMKIyMjIyMjIyMjIyMjIyMjIyMKbW9yZl9ERUdzX3Bsb3QgPC0gZnVuY3Rpb24oZ2VuZXMgPSBnZW5lc19lcGksIGNsdXM9Il41JHxeNiR8Xjd8XjgiKXsKICBkZiA8LSBEQVRBICU+JQogICAgbXV0YXRlKC4sIEZldGNoRGF0YSguLCB2YXJzID0gYyhuYW1lcyhnZW5lcykpLCBzbG90ID0gImNvdW50cyIpKSAlPiUKICAgIGZpbHRlciguLCBncmVwbChjbHVzLCAuJENsdXN0ZXJzKSkgJT4lCiAgICBhc190aWJibGUoKSAlPiUKICAgIHNlbGVjdCgxOjUsIGxheWVycywgYWxsX29mKG5hbWVzKGdlbmVzKSkpICU+JQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBhbnlfb2YobmFtZXMoZ2VuZXMpKSwgbmFtZXNfdG8gPSAiZ2VuZSIsIHZhbHVlc190byA9ICJ2YWx1ZXMiKSAlPiUKICAgICMgZmlsdGVyKGdlbmUgPT0gIkxHQUxTNyIpICU+JQogICAgZ3JvdXBfYnkoIGdyb3VwcywgZ2VuZSwgbGF5ZXJzKSAlPiUKICAgIHN1bW1hcml6ZShzdW1fY291bnRzID0gc3VtKHZhbHVlcyksIC5ncm91cHM9ImRyb3AiKSAlPiUKICAgIG11dGF0ZSgiU3VtIGNvdW50cyhsb2cxMCkiID0gbG9nMTAoLiRzdW1fY291bnRzKSkgJT4lCiAgICBhcnJhbmdlKGBTdW0gY291bnRzKGxvZzEwKWApICU+JQogICAgbXV0YXRlKHR5cGUgPSBnZW5lc1suJGdlbmVdKQogIAogIGFic21heCA8LSBmdW5jdGlvbih4KSB7IHhbd2hpY2gubWF4KCBhYnMoeCkgKV19CiAgb3JkIDw8LSBkZiAlPiUKICAgICNwaXZvdF93aWRlcihpZF9jb2xzID0gLWBTdW0gY291bnRzKGxvZzEwKWAsbmFtZXNfZnJvbSA9ICJncm91cHMiLCB2YWx1ZXNfZnJvbSA9ICJzdW1fY291bnRzIikgJT4lCiAgICBwaXZvdF93aWRlcihpZF9jb2xzID0gLXN1bV9jb3VudHMsIG5hbWVzX2Zyb20gPSAiZ3JvdXBzIiwgdmFsdWVzX2Zyb20gPSBgU3VtIGNvdW50cyhsb2cxMClgKSAlPiUKICAgIG11dGF0ZShkaWZmX0wxX0w0ID0gTDQtTDEsIAogICAgICAgICAgIGRpZmZfTDJfTDQgPSBMNC1MMiwgCiAgICAgICAgICAgZGlmZl9MM19MNCA9IEw0LUwzLCAuYnkgPSAiZ2VuZSIpICU+JQogICAgcm93d2lzZSgpICU+JSAKICAgICMgSWRlbnRpZmllcyB0aGUgbGFyZ2VzIHZhbHVlIG9mIGVhaCByb3cgYW1vbmcgdGhlIEwxLUw0IGNvbHVtbnM6CiAgICBtdXRhdGUoUmVndWxhdGlvbiA9IHN1bShjX2Fjcm9zcyhzdGFydHNfd2l0aCgiZGlmZiIpKSApLAogICAgICAgICAgIG1heCA9IHBhc3RlMChuYW1lcyguWzQ6N10pW2NfYWNyb3NzKHN0YXJ0c193aXRoKCJMIixpZ25vcmUuY2FzZT1GKSkgPT0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhYnNtYXgoY19hY3Jvc3Moc3RhcnRzX3dpdGgoIkwiLGlnbm9yZS5jYXNlPUYpKSldLCBjb2xsYXBzZSA9ICdfJykgKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShSZWd1bGF0aW9uID0gaWZlbHNlKC4kUmVndWxhdGlvbiA8IDAsICJET1dOIiwgIlVQIiksCiAgICAgICAgICAgbWF4ID0gc3RyX2V4dHJhY3QoLiRtYXgsICJMXFxkIikpCiAgCiAgbSA8LSBpZmVsc2UoY2x1cyA9PSAiXjUkfF42JHxeN3xeOCIsICJFcGl0aGVsaWFsIiwgIlN1Ym11Y29zYWwiKQogICN3cml0ZS54bHN4KG9yZCwgcGFzdGUwKHJlc3VsdF9kaXIsICJTZWxlY3RlZF9ERUdzX0ZJRzItM18iLCBtLCAiLnhsc3giKSkKICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICAjIFRPUCBERUdzIFBMT1RUSU5HICMKICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICBnX29yZCA8LSBhcnJhbmdlKG9yZCwgZGlmZl9MMV9MNCkgJT4lIHB1bGwoImdlbmUiKSAlPiUgdW5pcXVlKCkKICAKICBjb2wgPC0gYygiTDEiPSIjRkY3RjAwIiwgIkwyIj0iI0ZFRDlBNiIsICJMMyI9IiM2QTUxQTMiLCAiTDQiPSIjOUU5QUM4IiApICMgIiNGRkZGQjMiLCAiI0JFQkFEQSIsIiM4REQzQzciLCAiI0ZCODA3MiIsCiAgY29sIDwtIGMoIkwxIj0iIzU2QjRFOSIsIkwyIj0iIzAwOUU3MyIsIkwzIj0iI0NDNzlBNyIsICJMNCI9IiNGQzhENjIiKQogIAogIChCIDwtIGxlZnRfam9pbihkZiwgc2VsZWN0KG9yZCwgUmVndWxhdGlvbiwgbWF4LCBnZW5lKSwgYnk9ImdlbmUiKSAlPiUKICAgICAgI211dGF0ZSguLCBnZW5lID0gZmFjdG9yKGdlbmUsIGxldmVscz1nX29yZCkpICU+JQogICAgICBnZ3Bsb3QyOjpnZ3Bsb3QoZGF0YT0uLCBhZXMoeD1mY3RfcmVvcmRlcjIoZ2VuZSwgUmVndWxhdGlvbixgU3VtIGNvdW50cyhsb2cxMClgKSwgeT1gU3VtIGNvdW50cyhsb2cxMClgKSkgKwogICAgZ2VvbV9wb2ludChhZXMoY29sPWdyb3VwcyksIHNpemUgPSAyKSArCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbCkgKwogICAgZmFjZXRfZ3JpZChjb2xzPXZhcnMoKSwgcm93cyA9IHZhcnMobGF5ZXJzKSwgc2NhbGVzID0gImZyZWVfeCIsIHNwYWNlID0gImZyZWVfeCIpICsKICAgICNmYWNldF93cmFwKCJtYXgiLCBuY29sID0gMiwgc3RyaXAucG9zaXRpb24gPSAidG9wIiwgc2NhbGVzID0gImZyZWVfeCIsIHNocmluayA9IEYpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDUsLTEsNSwxKSx1bml0cyA9ICJwdCIpLAogICAgICAgICAgbGVnZW5kLm1hcmdpbiA9IG1hcmdpbigtMTUsMiwtOCwyKSwgIyBtb3ZlcyB0aGUgbGVnZW5kIGJveAogICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgICAgbGVnZW5kLnNwYWNpbmcueCA9IHVuaXQoNCwgJ3B0JyksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9OCksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTgsIGFuZ2xlPTQ1LCBoanVzdD0xLCBjb2xvcj0iYmxhY2siKSwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICN0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICApICkKfQpnZW5laWQgIDwtIGMoIklHSEc0IiwgIklHTEMyIiwgIklHSEcxIiwgIklHSEEyIiwgIklHSEExIikKZ2VuZXMgPC0gREVHc190YWJsZSAlPiUgZmlsdGVyKGdlbmUgJWluJSBnZW5laWQpICU+JSBmaWx0ZXIoZ3JlcGwoIl4xJHxCYXNhbCIsIC4kbGF5ZXJzKSkgJT4lIGRpc3RpbmN0KGdlbmUsIGxheWVycykgJT4lIGRlZnJhbWUoKQooSW1tdW5vIDwtIG1vcmZfREVHc19wbG90KGdlbmVzID0gZ2VuZXMsIGNsdXM9Il4xJHw4IikpCmBgYAoKCmBgYHtyIHZpb2xpbi1wbG90LCBmaWcud2lkdGg9NCxmaWcuaGVpZ2h0PTR9CiMjIyMjIyMjIyMjIyMjIwojIFZJT0xJTiBQTE9UICMKIyMjIyMjIyMjIyMjIyMjCiMgaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzU3MTczNTMvc3BsaXQtdmlvbGluLXBsb3Qtd2l0aC1nZ3Bsb3QyCgpmZWF0dXJlIDwtIGMoIklHSEc0IiwgIklHTEMyIiwgIklHSEcxIiwgIklHSEEyIiwgIklHSEExIiwgIkNEODEiLCAiSUdLQyIsICJKQ0hBSU4iKQpmZWF0dXJlIDwtIGMoIklHSEExIiwiSUdIRzEiLCAiQ0Q4MSIsICJJR0tDIiwgIkpDSEFJTiIpCmNvbCA8LSBjKCJMMSI9IiM1NkI0RTkiLCJMMiI9IiMwMDlFNzMiLCJMMyI9IiNDQzc5QTciLCAiTDQiPSIjRkM4RDYyIikKZmFjZXQgPC0gImxheWVycyIKZ3JvdXAuYnkgPC0gImdyb3VwcyIKbmNvbCA8LSAxCgpERUdzX2RmIDwtIERBVEEgJT4lCiAgI2ZpbHRlcighKGdyZXBsKCJcXGQiLCAuJGxheWVycykpKSAlPiUKICBmaWx0ZXIoKGdyZXBsKCJCYXNhbHxeMSQiLCAuJGxheWVycykpKSAlPiUKICBmaWx0ZXIoKGdyZXBsKCJMMXxMMiIsIC4kZ3JvdXBzKSkpICU+JQogIG11dGF0ZSguLCBGZXRjaERhdGEoLiwgdmFycyA9IGMoZmVhdHVyZSkpICkgJT4lCiAgI211dGF0ZShhY3Jvc3MoYW55X29mKGZlYXR1cmUpLCBuYV9pZiwgMCkpICU+JSAjIE5CISByZW1vdmVzIHplcm8gdmFsdWVzIAogIHNlbGVjdChhbnlfb2YoYyhmZWF0dXJlLCBmYWNldCwgZ3JvdXAuYnksICJsYXllcnMiKSkpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYW55X29mKGZlYXR1cmUpLCBuYW1lc190byA9ICJmZWF0dXJlIiwgdmFsdWVzX3RvID0gInZhbCIpICU+JQogIG11dGF0ZShjb21iID0gcGFzdGUwKC4kZ3JvdXBzLCAiXyIsLiRsYXllcnMpKSAlPiUKICBtdXRhdGUoZ3JvdXBzID0gZmFjdG9yKC4kZ3JvdXBzLCBsZXZlbHMgPSBzb3J0KHVuaXF1ZSguJGdyb3VwcykpKSkKCiMgZ3JvdXBzIG9uIHktYXhpcywgZ2VuZXMgb24geCBheGlzCiMgbm90IHVzZWQ6CnZpb2xpbl9tZWFuX3Bsb3QgPC0gZnVuY3Rpb24oREVHc19kZil7CiAgbSA8LSBtYXgobmEub21pdChERUdzX2RmW1sidmFsIl1dKSkvMSAjIHRyeSBlLmcgMgogIERFR3NfZGYgJT4lCiAgICBnZ3Bsb3QoYWVzKHk9LmRhdGFbW2dyb3VwLmJ5XV0sIHg9LmRhdGFbWyJ2YWwiXV0sIGNvbD0uZGF0YVtbZ3JvdXAuYnldXSkpICsKICAgIGdlb21fdmlvbGluKCkgKyAjIHtpZihsZW5ndGgoZmVhdHVyZSA9PSAxKSkgZ2d0aXRsZShmZWF0dXJlKX0gKwogICAgI2dlb21fYm94cGxvdChmaWxsID0gInRyYW5zcGFyZW50Iiwgbm90Y2ggPSBULCBvdXRsaWVyLnNpemUgPSAuNSwgb3V0bGllci5jb2xvdXIgPSAicmVkIikgKwogICAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjIsIGhlaWdodCA9IDAuMywgYWxwaGEgPSAwLjIsIHNpemU9LjEpICsKICAgIHN0YXRfc3VtbWFyeShhZXMoeCA9IHZhbCksIGZ1bj1tZWRpYW4sIGdlb209ImNyb3NzYmFyIiwgbGluZXdpZHRoPS4zLCBjb2xvcj0iYmxhY2siKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sKSArCiAgICBteV90aGVtZSArIE5vTGVnZW5kKCkgKyAjeGxpbShjKDAsIG0pKSArCiAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICAgICMgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3Q9MSksCiAgICAjICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgIyAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAjICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgI2ZhY2V0X3dyYXAofi5kYXRhW1tmYWNldF1dLCBuY29sID0gbmNvbCwgc3RyaXAucG9zaXRpb24gPSBjKCJyaWdodCIsICJib3R0b20iLCAibGVmdCIsICJ0b3AiKSkKICAgIGZhY2V0X2dyaWQocm93cyA9IHZhcnMobGF5ZXJzKSwgY29scyA9IHZhcnMoZmVhdHVyZSkpICMsIHN0cmlwLnBvc2l0aW9uID0gYygicmlnaHQiLCAiYm90dG9tIiwgImxlZnQiLCAidG9wIikpCn0KCiMgZGV2Lm5ldyh3aWR0aD02LjcsIGhlaWdodD0zLCBub1JTdHVkaW9HRCA9IFRSVUUpIApBIDwtIHZpb2xpbl9tZWFuX3Bsb3QoREVHc19kZikKIyBnZ3NhdmUoIi4vRmlndXJlcy8wNC9GaWdfdmlvbC5wbmciLCBBLCB3aWR0aCA9IDYuNywgaGVpZ2h0ID0gMykgIywgZHBpID0gMzAwCgojIGdyb3VwcyBvbiB4LWF4aXMsIGdlbmVzIG9uIHggYXhpcwojIHVzZWQgZm9yIGZpZ3VyZSA0CnZpb2xpbl9tZWFuX3Bsb3QgPC0gZnVuY3Rpb24oREVHc19kZil7CiAgbSA8LSBtYXgobmEub21pdChERUdzX2RmW1sidmFsIl1dKSkvMSAjIHRyeSBlLmcgMgogIERFR3NfZGYgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9LmRhdGFbW2dyb3VwLmJ5XV0sIHk9LmRhdGFbWyJ2YWwiXV0sIGNvbD0uZGF0YVtbZ3JvdXAuYnldXSkpICsKICAgIGdlb21fdmlvbGluKCkgKyAjIHtpZihsZW5ndGgoZmVhdHVyZSA9PSAxKSkgZ2d0aXRsZShmZWF0dXJlKX0gKwogICAgc3RhdF9zdW1tYXJ5KGFlcyh5ID0gdmFsKSwgZnVuPW1lZGlhbiwgZ2VvbT0iY3Jvc3NiYXIiLCBsaW5ld2lkdGg9LjMsIGNvbG9yPSJibGFjayIpICsKICAgICNnZW9tX2JveHBsb3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIG5vdGNoID0gVCwgb3V0bGllci5zaXplID0gLjUsIG91dGxpZXIuY29sb3VyID0gInJlZCIpICsKICAgIGdlb21faml0dGVyKHdpZHRoID0gMC4zLCBoZWlnaHQgPSAwLjIsIGFscGhhID0gMC4yLCBzaXplPS4wMSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbCkgKyB5bGFiKCJFeHByZXNzaW9uIikgKwogICAgbXlfdGhlbWUgKyBOb0xlZ2VuZCgpICsgI3hsaW0oYygwLCBtKSkgKwogICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmF5IikgKSArCiAgICAjICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0PTEpLAogICAgIyAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICMgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgIyAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgICNmYWNldF93cmFwKH4uZGF0YVtbZmFjZXRdXSwgbmNvbCA9IG5jb2wsIHN0cmlwLnBvc2l0aW9uID0gYygicmlnaHQiLCAiYm90dG9tIiwgImxlZnQiLCAidG9wIikpCiAgICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGxheWVycyksIGNvbHMgPSB2YXJzKGZlYXR1cmUpKSAjLCBzdHJpcC5wb3NpdGlvbiA9IGMoInJpZ2h0IiwgImJvdHRvbSIsICJsZWZ0IiwgInRvcCIpKQp9CgojIGRldi5uZXcod2lkdGg9My4zLCBoZWlnaHQ9Mywgbm9SU3R1ZGlvR0QgPSBUUlVFKSAKQSA8LSB2aW9saW5fbWVhbl9wbG90KERFR3NfZGYpCiMgZ2dzYXZlKCIuL0ZpZ3VyZXMvMDQvRmlnX0wxX0wyX3Zpb2wucG5nIiwgQSwgd2lkdGggPSA0LCBoZWlnaHQgPSA0LCBkcGkgPSA1MDApICMsIGRwaSA9IDMwMApgYGAKCmBgYHtyIGdlbmVzLW9uLXRpc3N1ZV9hbGxfSUQsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9OH0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFBMT1RUSU5HIE9OIFRJU1NVRSAjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKY29sID0gYygiI0VGRURGNSIsICIjREFEQUVCIiwgIiNCQ0JEREMiLCAiIzlFOUFDOCIsICIjODA3REJBIiwgIiM2QTUxQTMiLCAiIzU0Mjc4RiIsICIjM0YwMDdEIikKZ2VuZWlkIDwtIGMoIklHSEc0IiwgIklHTEMyIiwgIklHSEcxIiwgIklHSEEyIiwgIklHSEExIiwgIkNEODEiLCAiSUdLQyIsICJKQ0hBSU4iKQoKIyBnZ3NhdmUoIi4vRmlndXJlcy8wMiYwMy9UaXNzdWVfSW1tdW5vLnBuZyIsIHAsIHdpZHRoID0gMTIuNSwgaGVpZ2h0ID0gMTIuNSwgYmcgPSAid2hpdGUiKSAjLCBkcGkgPSAzMDAKIyBkZXYubmV3KGhlaWdodD0zLCB3aWR0aD03LCBub1JTdHVkaW9HRCA9IFRSVUUpCnBsb3RzX2FsbCA8LSBnZW5laWQgJT4lCiAgbWFwKC4sIH5wbG90X3NwYXRpYWwuZnVuKAogICAgICBEQVRBLAogICAgICBzYW1wbGVpZCA9IHNhbXBsZV9pZCwKICAgICAgc2F2ZV9zcGFjZSA9IFQsCiAgICAgIGNvbG9ycyA9IGNvbCwgCiAgICAgIGdlbmVpZCA9IC54LAogICAgICB6b29tID0gInpvb20iLAogICAgICBuY29sID0gNCwKICAgICAgaW1nX2FscGhhID0gMCwKICAgICAgcG9pbnRfc2l6ZSA9IC41KQogICAgKQoKIyBkZXYubmV3KHdpZHRoPTgsIGhlaWdodD04LCBub1JTdHVkaW9HRCA9IFRSVUUpCnBsb3RzX2FsbFtbMV1dCgojIyMjIyMjIyMjIyMjIyMjCiMgU0FWRSBSRVNVTFRTICMKIyMjIyMjIyMjIyMjIyMjIwpwZGYoZmlsZT1wYXN0ZTAoIi4vRmlndXJlcy8wNC9UaXNzdWVfSW1tdW5vX2FsbC5wZGYiKSwgCiAgICAjd2lkdGggPSA4LjUsIGhlaWdodCA9IDEwICMgRXBpCiAgICB3aWR0aCA9IDgsIGhlaWdodCA9IDggIyBTdWIKKQpwbG90c19hbGwKZGV2Lm9mZigpCgpgYGAKCmBgYHtyIG9uX3Rpc3N1ZSwgZmlnLndpZHRoPTQsZmlnLmhlaWdodD0zLjN9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBQTE9UVElORyBPTiBUSVNTVUUgIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnNhbXBsZV9pZF8gPC0gYygiUDA1NyIsIlAwNDQiKQoKCnBsb3RzX3JlcCA8LSBnZW5laWQgJT4lCiAgbWFwKC4sIH5wbG90X3NwYXRpYWwuZnVuKAogICAgICBEQVRBLAogICAgICBzYW1wbGVpZCA9IHNhbXBsZV9pZF8sCiAgICAgIHNhdmVfc3BhY2UgPSBGLAogICAgICBjb2xvcnMgPSBjb2wsIAogICAgICBnZW5laWQgPSAueCwKICAgICAgem9vbSA9ICJ6b29tIiwKICAgICAgbmNvbCA9IDQsCiAgICAgIGltZ19hbHBoYSA9IDAsCiAgICAgIHBvaW50X3NpemUgPSAuNSkKICAgICkKIyBkZXYubmV3KHdpZHRoPTMuMywgaGVpZ2h0PTIsIG5vUlN0dWRpb0dEID0gVFJVRSkKcGxvdHNfcmVwW1sxXV0KCkIgPC0gcGxvdF9ncmlkKHBsb3RzX3JlcFtbOF1dLCBwbG90c19yZXBbWzVdXSwgbmNvbCA9IDEpCiMgZ2dzYXZlKCIuL0ZpZ3VyZXMvMDQvb25fdGlzc3VlLnBuZyIsIEIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMy4zLCBiZyA9ICJ3aGl0ZSIsIGRwaSA9IDUwMCkgIywgZHBpID0gMzAwCmBgYAoKCmBgYHtyIEZJR1VSRTQsIGZpZy53aWR0aD02LjcsZmlnLmhlaWdodD0zfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgQ09NQklORSBQQU5FTCBBIEFORCBCICMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIGRldi5uZXcod2lkdGg9Ni43LCBoZWlnaHQ9Mywgbm9SU3R1ZGlvR0QgPSBUUlVFKSAKKEZJR1VSRTQgPC0gcGxvdF9ncmlkKEEsIEIsIHJlbF93aWR0aHMgPSBjKDEsIDEpKSkgIyBsYWJlbHMgPSBjKCJhIiwgImIiKQojIGdnc2F2ZSgiLi9GaWd1cmVzLzA0L0ZpZ3VyZV80LnBuZyIsIHAsIHdpZHRoID0gNi43LCBoZWlnaHQgPSAzLjMsIGJnID0gIndoaXRlIikgIywgZHBpID0gMzAwCmBgYAoK